<?php

namespace app\storeapi\model;

use app\common\enum\order\PayType as PayTypeEnum;
use app\common\model\Order as OrderModel;
use app\common\model\User as UserModel;
use app\storeapi\model\UserCoupon as UserCouponModel;
use app\common\enum\OrderType as OrderTypeEnum;
use app\common\enum\DeliveryType as DeliveryTypeEnum;
use app\common\service\Message as MessageService;
use app\common\service\order\Refund as RefundService;
use app\common\service\wechat\wow\Order as WowService;
use app\common\service\goods\source\Factory as FactoryStock;
use think\Db;

/**
 * 地区管理控制器
 * Class Region
 * @package app\store\model
 */
class Order extends OrderModel
{

    /**
     * 设置检索查询条件
     * @param $query
     */
    private function setWhere($query)
    {

        if (isset($query['start_time']) && !empty($query['start_time'])) {
            $this->where('order.create_time', '>=', strtotime($query['start_time']));
        }
        if (isset($query['end_time']) && !empty($query['end_time'])) {
            $this->where('order.create_time', '<', strtotime($query['end_time']) + 86400);
        }
        if (isset($query['delivery_type']) && !empty($query['delivery_type'])) {
            $query['delivery_type'] > -1 && $this->where('delivery_type', '=', $query['delivery_type']);
        }
        if (isset($query['extract_shop_id']) && !empty($query['extract_shop_id'])) {
            $query['extract_shop_id'] > -1 && $this->where('extract_shop_id', '=', $query['extract_shop_id']);
        }
        // 用户id
        if (isset($query['user_id']) && $query['user_id'] > 0) {
            $this->where('order.user_id', '=', (int)$query['user_id']);
        }

    }

    /**
     * 转义数据类型条件
     * @param $dataType
     * @return array
     */
    private function transferDataType($dataType)
    {
        // 数据类型
        $filter = [];
        switch ($dataType) {
            case 'delivery': //待发货
                $filter = [
                    'pay_status' => 20,
                    'delivery_status' => 10,
                    'order_status' => ['in', [10]]
                ];
                break;
            case 'receipt'://待收货
                $filter = [
                    'pay_status' => 20,
                    'delivery_status' => 20,
                    'receipt_status' => 10
                ];
                break;
            case 'pay'://待付款
                $filter = ['pay_status' => 10, 'order_status' => 10];
                break;
            case 'complete'://已完成
                $filter = ['order_status' => 30];
                break;
            case 'preparCancel'://已取消
                $filter = ['order_status' => 21];
                break;
            case 'cancel'://已取消
                $filter = ['order_status' => 20];
                break;
            case 'all':
                $filter = [];
                break;
        }
        return $filter;
    }

    /**
     * 订单列表
     * @param string $dataType
     * @param array $query
     * @return \think\Paginator
     * @throws \think\exception\DbException
     */
    public function getList($param)
    {
        $page = isset($param['page']) && is_numeric($param['page']) ? intval($param['page']) : 1;
        $limit = 10;
        $offset = ($page - 1) * $limit;
        // 检索查询条件
        $this->setWhere($param);

        // 获取数据列表
        //$data =  $this->with(['goods.image', 'address', 'user'])
        $data =  $this->with(['goods.image'])
            ->alias('order')
            ->field('order.order_id,order.order_no,order.pay_price,order.pay_type,order.order_status,pay_status,delivery_status,receipt_status')
            ->join('user', 'user.user_id = order.user_id')
            ->where($this->transferDataType($param['type']))
            ->where('order.is_delete', '=', 0)
            ->where(['order.order_source'=>['IN',[10,20,30]]])
            ->order(['order.create_time' => 'desc'])
            ->limit($offset, $limit)
            ->select();

        return $data;
    }

    /**
     * 订单商品列表
     * @return \think\model\relation\HasMany
     */
    public function goods()
    {
        return $this->hasMany("OrderGoods");
    }

    /**
     * 确认发货(单独订单)
     * @param $data
     * @return array|bool|false
     * @throws \app\common\exception\BaseException
     * @throws \think\Exception
     * @throws \think\exception\DbException
     * @throws \Exception
     */
    public function delivery($data)
    {
        // 转义为订单列表
        $orderList = [$this];
        // 验证订单是否满足发货条件
        if (!$this->verifyDelivery($orderList)) {
            return false;
        }
        if(!trim($data['express_id'])){
            $this->error = "请选择物流公司!";
            return false;
        }
        if(!trim($data['express_no'])){
            $this->error = "请输入物流单号!";
            return false;
        }
        // 整理更新的数据
        $updateList = [[
            'order_id' => $this['order_id'],
            'express_id' => $data['express_id'],
            'express_no' => $data['express_no']
        ]];
        // 更新订单发货状态
        if ($status = $this->updateToDelivery($updateList)) {
            // 获取已发货的订单
            $completed = self::detail($this['order_id'], ['user', 'address', 'goods', 'express']);
            // 发送消息通知
            $this->sendDeliveryMessage([$completed]);
            // 同步好物圈订单
            (new WowService($this['wxapp_id']))->update([$completed]);
        }
        return $status;
    }


    /**
     * 验证订单是否满足发货条件
     * @param $orderList
     * @return bool
     */
    private function verifyDelivery($orderList)
    {
        foreach ($orderList as $order) {
            if (
                $order['pay_status']['value'] != 20
                || $order['delivery_type']['value'] != DeliveryTypeEnum::EXPRESS
                || $order['delivery_status']['value'] != 10
            ) {
                $this->error = "订单号[{$order['order_no']}] 不满足发货条件!";
                return false;
            }
        }
        return true;
    }


    /**
     * 更新订单发货状态(批量)
     * @param $orderList
     * @return array|false
     * @throws \Exception
     */
    private function updateToDelivery($orderList)
    {
        $data = [];
        foreach ($orderList as $item) {
            $data[] = [
                'order_id' => $item['order_id'],
                'express_no' => $item['express_no'],
                'express_id' => $item['express_id'],
                'delivery_status' => 20,
                'delivery_time' => time(),
            ];
        }
        return $this->isUpdate()->saveAll($data);
    }

    /**
     * 审核：用户取消订单
     * @param $data
     * @return bool|mixed
     * @throws \app\common\exception\BaseException
     * @throws \think\exception\DbException
     */
    public function confirmCancel($data)
    {

        // 判断订单是否有效
        if ($this['pay_status']['value'] != 20) {
            $this->error = '该订单不合法';
            return false;
        }
        // 订单取消事件
        $status = $this->transaction(function () use ($data) {
            if ($data['is_cancel'] == true) {
                // 执行退款操作
                (new RefundService)->execute($this);
                // 回退商品库存
                FactoryStock::getFactory($this['order_source'])->backGoodsStock($this['goods'], true);
                // 回退用户优惠券
                $this['coupon_id'] > 0 && UserCouponModel::setIsUse($this['coupon_id'], false);
                // 回退用户积分
                $User = (new UserModel)->detail($this['user_id']);
                $describe = "订单取消：{$this['order_no']}";
                $this['points_num'] > 0 && $User->setIncPoints($this['points_num'], $describe);
                // 回退用户零钱
                $this['balance_num'] > 0 && $User->setIncBalance($this['balance_num'], $describe,40);
            }
            // 更新订单状态
            return $this->save(['order_status' => $data['is_cancel'] ? 20 : 10]);
        });
        if ($status == true) {
            // 同步好物圈订单
            (new WowService(self::$wxapp_id))->update([$this]);
        }
        return $status;
    }


    /**
     * 确认发货后发送消息通知
     * @param $orderList
     * @return bool
     */
    private function sendDeliveryMessage($orderList)
    {
        // 发送消息通知
        foreach ($orderList as $item) {
            MessageService::send('order.delivery', [
                'order' => $item,
                'order_type' => OrderTypeEnum::MASTER,
            ]);
        }
        return true;
    }


    /**
     * 获取今日的流水
     * @param $orderList
     * @return bool
     */
    public static function todayMoney($param){

        $startTime = strtotime(date("Y-m-d"),time());
        $endTime = $startTime+24*60*60;
        $db = db();
        $sql = "
        SELECT SUM(allmoney.pay_price) as allmoney FROM( SELECT pay_price FROM  yoshop_gifts_order WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20   AND to_days(pay_time) BETWEEN {$startTime} AND {$endTime}  UNION  ALL SELECT pay_price FROM  yoshop_order WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20 AND `pay_time`  BETWEEN {$startTime} AND {$endTime}) AS allmoney;
        ";

        $log = $db->query($sql);
        return bcadd($log[0]['allmoney'],0,2);
    }

    /**
     * 获取全部的流水
     * @param $orderList
     * @return bool
     */
    public static function allMoney($param){
        $db = db();
        $sql = "
        SELECT SUM(allmoney.pay_price) as allmoney FROM(SELECT pay_price FROM  yoshop_gifts_order WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20 UNION  ALL SELECT pay_price  FROM  yoshop_order WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20) AS allmoney;
        ";
        $log = $db->query($sql);
        return bcadd($log[0]['allmoney'],0,2);
    }

    /**
     * 获取今日的金额
     * @param $orderList
     * @return bool
     */
    public static function logMoney($param){


        //流水明细
        $page = isset($param['page']) && is_numeric($param['page']) ? intval($param['page']) : 1;
        $limit = 10;
        $offset = ($page - 1) * $limit;

        if(!empty($param['search'])){
            $where = "`a`.`wxapp_id` = {$param['wxapp_id']} AND `a`.`pay_status` = 20 AND `b`.`nickName` LIKE '%{$param['search']}%' ";
        }else{
            $where = "`a`.`wxapp_id` = {$param['wxapp_id']} AND `a`.`pay_status` = 20 ";
        }

        $db = db();
        $sql = "
        (SELECT `a`.`order_id`,`a`.`pay_price`,`a`.`pay_time`,`a`.`pay_status`,`b`.`nickName` 
        FROM `yoshop_order` `a` LEFT JOIN `yoshop_user` `b` ON `a`.`user_id`=`b`.`user_id` 
        WHERE  {$where})
        UNION
        (SELECT `a`.`order_id`,`a`.`pay_price`,`a`.`pay_time`,`a`.`pay_status`,`b`.`nickName` 
        FROM `yoshop_gifts_order` `a` LEFT JOIN `yoshop_user` `b` ON `a`.`user_id`=`b`.`user_id` 
        WHERE  {$where})
        ORDER BY `pay_time` DESC LIMIT {$offset},{$limit}
        ";

        $log = $db->query($sql);

        foreach($log as $k=>&$v){
            $v['pay_time'] = date('Y-m-d H:i:s',$v['pay_time']);
        }

        return $log;
    }


    /**
     * 获取收款笔数
     * @param $orderList
     * @return bool
     */
    public static function logGetMoney($param){
        // 筛选条件
        $filter = [];
        $filter['wxapp_id'] = $param['wxapp_id'];
        $filter['pay_status'] = 20;

        if (isset($param['start_time']) && !empty($param['start_time'])) {
            $filter['pay_time'] = ['>=',strtotime($param['start_time'])];
        }
        if (isset($param['end_time']) && !empty($param['end_time'])) {
            $filter['pay_time'] = ['<',strtotime($param['end_time']) + 86400];
        }
        if (!empty($param['end_time']) && !empty($param['end_time'])) {
            $filter['pay_time'] = ['between',[strtotime($param['start_time']),strtotime($param['end_time']) + 86400]];
        }
        //普通收款笔数
        $countOrder = (new static())->where($filter)->count()?:0;
        //普通收款金额
        $priceOrder = (new static())->where($filter)->sum('pay_price')?:0;

        //爆品收款笔数
        $countGiftsOrder = db('gifts_order')->where($filter)->count()?:0;
        //爆品收款金额
        $priceGiftsOrder = db('gifts_order')->where($filter)->sum('pay_price')?:0;

        $count = bcadd($countOrder,$countGiftsOrder,0);
 
        $price = bcadd($priceOrder,$priceGiftsOrder,2);

        $wxapp_id = $param['wxapp_id'];
        $startTime = strtotime($param['start_time']);
        $endTime = strtotime($param['end_time']) + 86400;

        $page = isset($param['page']) && is_numeric($param['page']) ? intval($param['page']) : 1;
        $limit = 10;
        $offset = ($page - 1) * $limit;

        $db = db();
        $sql = "
        (SELECT `order_id`,`order_no`,`pay_price`,`pay_time`,`pay_status`,`pay_type` ,`order_source`
        FROM `yoshop_order` 
        WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20  AND `pay_time` BETWEEN {$startTime}  AND {$endTime})
        UNION
        (SELECT `order_id`,`order_no`,`pay_price`,`pay_time`,`pay_status`,`pay_type` ,5 as `order_source`   
        FROM `yoshop_gifts_order` 
        WHERE  `wxapp_id` = {$param['wxapp_id']}  AND `pay_status` = 20  AND `pay_time` BETWEEN {$startTime}  AND {$endTime})   
        ORDER BY `pay_time` DESC LIMIT {$offset},{$limit}
        ";

        $log = $db->query($sql);

        foreach($log as $k=>&$v){
            $v['pay_time'] = date('Y-m-d H:i:s',$v['pay_time']);
            $v['pay_type'] = static::payTypeAttr($v['pay_type']);
        }

        return compact('count','price','log');
    }

    /**
     * 付款状态
     * @param $value
     * @return array
     */
    public static function payTypeAttr($value)
    {
        return ['text' => PayTypeEnum::data()[$value]['name'], 'value' => $value];
    }

    /**
     * 经营报表
     * @param $orderList
     * @return bool
     */
    public static function reportFrom($param){
        // 筛选条件
        $filter = [];
        $filter['wxapp_id'] = $param['wxapp_id'];
        $filter['pay_status'] = 20;

        $refundfilter = [];
        $refundfilter['wxapp_id'] = $param['wxapp_id'];

        $whereTime = [];
        $type = $param['type'];
        switch ($type) {
            case 'day': //日报
                $whereTime = ['pay_time','today'];
                break;
            case 'week'://月报
                $whereTime = ['pay_time','week'];
                break;
            case 'year'://年报
                $whereTime = ['pay_time','year'];
                break;
        }

        if (isset($param['start_time']) && !empty($param['start_time'])) {
            $filter['pay_time'] = ['>=',strtotime($param['start_time'])];
            $refundfilter['create_time'] = ['>=',strtotime($param['start_time'])];
        }
        if (isset($param['end_time']) && !empty($param['end_time'])) {
            $filter['pay_time'] = ['<',strtotime($param['end_time']) + 86400];
            $refundfilter['create_time'] = ['<',strtotime($param['end_time']) + 86400];
        }
        if (!empty($param['end_time']) && !empty($param['end_time'])) {
            $filter['pay_time'] = ['between',[strtotime($param['start_time']),strtotime($param['end_time']) + 86400]];
            $refundfilter['create_time'] = ['between',[strtotime($param['start_time']),strtotime($param['end_time']) + 86400]];
        }

        //普通订单的总金额
        $orderPrice = (new static())->where($filter)->sum('pay_price')?:0;
        //爆品订单的总金额
        $giftsOrderPrice = db('gifts_order')->where($filter)->sum('pay_price')?:0;
        //总金额
        $allPrice = $orderPrice+$giftsOrderPrice;


        //普通订单总人数
        $orderUser = (new static())->where($filter)->group('user_id')->count()?:0;
        //爆品订单的总人数
        $giftsOrderUser = db('gifts_order')->where($filter)->group('user_id')->count()?:0;
        //总人数
        $allUser = bcadd($orderUser,$giftsOrderUser,0);

        //普通订单总笔数
        $orderCount = (new static())->where($filter)->count()?:0;
        //爆品订单总笔数
        $giftsOrderCount = db('gifts_order')->where($filter)->count()?:0;
        //总笔数
        $allCount = bcadd($orderCount,$giftsOrderCount,0);

        if($allPrice == 0 && $allCount == 0){
            $avgPrice = 0;
        }else{
            //单笔均价
            $avgPrice = bcadd($allPrice/$allCount,0,2);
        }

        //分红金额
        $canMoney=Db::name('divide_receives')
            ->where($refundfilter)
            ->field('(sum(total_abonus)) as fehmoney')
            ->find();
        $refundPrice = $canMoney['fehmoney']?:0;
        //分红笔数
        $refundCount = Db::name('divide_receives')
            ->where($refundfilter)
            ->sum('times');


        //余额支付总金额
        $filter['pay_type']=10;
        $yue = (new static())->where($filter)->sum('pay_price');

        //实收金额 =总销售额-余额支付金额-分红金额
        $onePrice = bcsub($allPrice,$yue,2);
        $allPrice = bcsub($onePrice,$refundPrice,2);

        return compact('allPrice','allUser','allCount','avgPrice','refundPrice','refundCount','yue');
    }


    /**
     * 付款时间
     * @param $value
     * @return array
     */
    public function getPayTimeAttr($value)
    {
        return $value?date('Y-m-d H:i:s',$value):"";
    }

}
